package tij4.concurrent.exercise.ex22;
//
//import java.sql.Time;
//import java.util.concurrent.ExecutorService;
//import java.util.concurrent.Executors;
//import java.util.concurrent.TimeUnit;
//
//class A implements Runnable {
//    private volatile boolean flag = false;
//
//    public boolean getFlag() {
//        return flag;
//    }
//
//    public void setFlag(boolean flag) {
//        this.flag = flag;
//    }
//
//    @Override
//    public void run() {
//        try {
//            TimeUnit.SECONDS.sleep(10);
//            flag = true;
//            System.out.println("A run()");
//        }catch (InterruptedException e){
//            System.out.println("A InterruptedException");
//        }
//    }
//}
//
//class B1 implements Runnable {
//    A a ;
//
//    public B1(A a) {
//        this.a = a;
//    }
//
//    public A getA() {
//        return a;
//    }
//
//    @Override
//    public void run() {
//       while (true) {
//           if (a.getFlag()) {
//               System.out.println("flag " + a.getFlag());
//               System.out.println("B a.setFalg false");
//               a.setFlag(false);
//           }
//       }
//    }
//}
//
//class B2 implements Runnable {
//    A a;
//
//    public A getA() {
//        return a;
//    }
//
//    public B2(A a) {
//        this.a = a;
//    }
//
//    public synchronized void run() {
//        while (true) {
//            if (a.getFlag()) {
//                System.out.println("flag true");
//                System.out.println("B a.setFalg false");
//                a.setFlag(false);
//                try {
//                    wait();
//                }catch (InterruptedException e) {
//                    System.out.println("B2 Interrupted");
//                }
//            }
//        }
//    }
//}
//
//public class Ex22 {
//    public static void main(String[] args) {
//        ExecutorService executorService = Executors.newCachedThreadPool();
//        A a = new A();
//        B1 b1 = new B1(a);
//        B2 b2 = new B2(a);
//        executorService.execute(b1.getA());
//        try {
//            TimeUnit.MILLISECONDS.sleep(500);
//        }catch (InterruptedException e) {
//            System.out.println("mian() sleep Interrupted");
//        }
////        executorService.execute(b1);
////        try {
////            TimeUnit.MILLISECONDS.sleep(25000);
////        }catch (InterruptedException e){
////            System.out.println("main() sleep Interrupted");
////        }
//        executorService.execute(b2);
//        try {
//            TimeUnit.MILLISECONDS.sleep(25000);
//        }catch (InterruptedException e) {
//            System.out.println("main() sleep Interrupted");
//        }
//        executorService.shutdownNow();
//
//    }
//}


import java.sql.Time;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

class A implements Runnable {
    boolean flag = false;

    public synchronized void run() {
        try {
            TimeUnit.SECONDS.sleep(2);
        }catch (InterruptedException e) {
            System.out.println("sleep interrupted in A");
        }
        System.out.println("A setting flag = true");
        flag = true;
    }
}

class BusyWait implements Runnable {
    A a = new A();
    long start, end;

    public synchronized A getA() {
        return a;
    }

    public BusyWait(A a) {
        this.a = a;
    }

    public static BusyWait buildBusyWait(A a) {
        return new BusyWait(a);
    }
    public synchronized void run() {
        System.out.println("Busy a.flag = " + a.flag);
        while (!Thread.interrupted()) {
            System.out.println("BusyWait run()");
            start = System.nanoTime();
            if (a.flag) {
                a.flag = false;
                System.out.println("BusyWait reset a.flag = false");
                end = System.nanoTime();
                System.out.println("Busy waiting " + (end - start) + " naonoseconds");
            }
        }
    }
}

class BetterWait implements Runnable {
    private A a = new A();

    public synchronized A getA() {
        return a;
    }
    public BetterWait(A a) {
        this.a = a;
    }
    public static BetterWait buildBetterWait(A a) {
        return new BetterWait(a);
    }
    public synchronized void run() {
        System.out.println("Better a.flag = " + a.flag);
        try {
            while (!a.flag) {
                wait();
                a.flag = false;
                System.out.println("BetterWait reset a.flag = false");
            }
        } catch (InterruptedException e) {
            System.out.println("BetterWait.run() interrupted");
        }
    }
}

public class Ex22 {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        BusyWait busyWait = BusyWait.buildBusyWait(new A());
        executorService.execute(busyWait.a);
        executorService.execute(busyWait);
        try {
            TimeUnit.SECONDS.sleep(3);
        }catch (InterruptedException e) {
            System.out.println("sleep interrupted in mian()");
        }
        System.out.println();
        BetterWait betterWait = BetterWait.buildBetterWait(new A());
        executorService.execute(betterWait.getA());
        executorService.execute(betterWait);
        try {
            TimeUnit.SECONDS.sleep(3);
        }catch (InterruptedException e) {
            System.out.println("sleep interrupted in mian()");
        }
        synchronized (betterWait) {
            System.out.println("Sending better.notifyAll()");
            betterWait.notifyAll();
        }
        executorService.shutdownNow();
    }
}
